const mongoose = require('mongoose')
const config = think.config('mongoose')
const createConnection = require('./socket')
module.exports = class Base {
  constructor (name) {
    if (config)createConnection(mongoose, config)
    this.mongoose = mongoose
    this.name = `${config.prefix}${name}`
    this.strict = this.strict || (typeof this.schema === 'function')
    const schema = new this.mongoose.Schema((this.schema ? this.schema() : {}), {
      collection: this.name,
      autoIndex: false,
      strict: this.strict,
      versionKey: false,
      timestamps: {
        createdAt: 'createdAt',
        updatedAt: 'updatedAt'
      }
    })
    this.createIndex && this.createIndex(schema)
    this.model = this.mongoose.model(this.name, schema)
    this.resetOpt()
  }
  resetOpt () {
    this.options = {
      where: {},
      sort: {_id: -1},
      field: '',
      distinct: false,
      current: 0,
      offset: 20
    }
  }
  where (o) {
    if (o) {
      this.options.where = o
    }
    return this
  }
  field (o) {
    if (o) {
      this.options.field = o
    }
    return this
  }
  limit (current, offset) {
    this.options.current = current
    this.options.offset = offset || this.options.offset
    return this
  }
  page (page, pageSize) {
    this.options.current = page - 1
    this.options.offset = pageSize || this.options.offset
    return this
  }
  order (o) {
    if (o) {
      this.options.sort = o
    }
    return this
  }
  distinct (o) {
    if (o) {
      this.options.distinct = o
    }
    return this
  }
  /**
   * 添加前aop实现
   * @param data 待添加的数据
   */
  beforeAdd (data) {
    return data
  }

  /**
   * 修改前aop实现
   * @param data 待修改的数据
   */
  beforeUpdate (data) {
    return data
  }

  /**
   * 单个查询后aop实现
   * @param data 待修改的数据
   */
  afterFind (data) {
    return data
  }

  /**
   * 多个查询后aop实现
   * @param data 待修改的数据
   */
  afterSelect (data) {
    return data
  }
  /**
   * 添加数据
   * @param data 待添加的数据
   */
  async add (data) {
    this.beforeAdd(data)
    const d = await this.model.create(data)
    return d
  }

  /**
   * 查询一条数据
   * @param condition 查询条件
   */
  async find () {
    const d = await this.model.findOne(this.options.where).select(this.options.field).lean()
    this.resetOpt()
    return this.afterFind(d)
  }
  /**
   * 插入或者更新
   * @param map
   * @param data
   * @returns {*|Query}
   */
  async findAndUpsert (data) {
    data = await this.model.findOneAndUpdate(this.options.where, data, {upsert: true}).lean()
    this.resetOpt()
    this.afterSelect(data)
  }

  /**
   * 获取条件数量
   * @param map
   */
  async count () {
    const d = await this.model.count(this.options.where)
    this.resetOpt()
    return d
  }
  /**
   * 查询多条数据
   * @returns {Promise.<*>}
   */
  async select () {
    const d = await this.model.find(
      this.options.where,
      {},
      {
        sort: this.options.sort,
        skip: this.options.current * this.options.offset,
        limit: this.options.offset
      }).select(this.options.field).lean()
    this.resetOpt()
    return this.afterSelect(d)
  }
  /**
   * 修改数据
   * @param condition 查询条件
   * @param data 要修改的数据
   */
  async update (data) {
    this.beforeUpdate(data)
    const d = await this.model.update(this.options.where, { $set: data }, { safe: true, strict: this.strict })
    this.resetOpt()
    return d.n
  }

  /**
   * 删除数据
   * @param condition 查询条件
   */
  async remove () {
    const d = await this.model.remove(this.options.where).lean()
    this.resetOpt()
    return d.n
  }

  /**
   * 自增(或者自减)
   * @param data 要自增的字段以及它的步长(例如：{times: 1})
   */
  async inc (o) {
    const d = await this.model.update(this.options.where, { $inc: o }, { multi: false, new: true })
    this.resetOpt()
    return d.n
  }

  /**
   * @param last 上一页游标
   * @param first 顶部游标
   */
  async cursor (first = '', last = '', pageSize = 20) {
    // 如果有上拉刷新的需求，则优先查询下拉刷新
    if (!think.isEmpty(first)) {
      think.extend(this.options.where, { _id: { $gt: first } })
    } else if (!think.isEmpty(last)) {
      // 否则才查询上拉刷新的
      think.extend(this.options.where, { _id: { $lt: last } })
    }

    // 查询
    const list = await this.model.find(this.options.where, {}, {
      sort: this.options.sort,
      limit: pageSize
    })

    first = list[0] ? list[0]._id : ''
    last = list[list.length - 1] ? list[list.length - 1]._id : ''
    this.resetOpt()
    this.afterSelect(list)
    return { list, last, first, pageSize }
  }
}
